//
//  AYBLEParameter.m
//  FuweiCloud
//
//  Created by michael on 2024/4/22.
//

#import "AYBLEParameter.h"
#import "AYBLEDeviceType.h"
#import "NSData+AYExtension.h"


@implementation AYBLEParameter {
    NSArray *_arguments;
    NSData *_data;
}

+ (NSArray<NSString *> *)propertyNames {
    return @[];
}

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        _data = data;
    }
    return self;
}

- (instancetype)initWithArguments:(NSArray *)arguments {
    if (self = [super init]) {
        NSArray *keys = [[self class] propertyNames];
        for (int i = 0; i < keys.count; i++) {
            if (i < arguments.count) {
                [self setValue:arguments[i] forKey:keys[i]];
            }
        }
    }
    return self;
}

- (instancetype)initWithArguments:(NSArray *)arguments format:(NSString *)format {
    if (self = [super init]) {
        NSAssert(format.length == arguments.count*2, @"format length error");
        _arguments = arguments;
        NSMutableData *argData = [NSMutableData data];
        int idx = 0;
        for (int i = 0; i < arguments.count; i++) {
            NSInteger len = [[format substringWithRange:NSMakeRange(idx, 2)] integerValue];
            NSAssert(len > 0, @"format data error");
            if ([arguments[i] isKindOfClass:[NSNumber class]]) {
                uint64_t num = [arguments[i] unsignedLongLongValue];
                [argData appendData:[NSData dataWithBytes:&num length:len]];
            }else if ([arguments[i] isKindOfClass:[NSString class]]) {
                [argData appendData:[(NSString *)arguments[i] dataUsingEncoding:NSUTF8StringEncoding]];
                [argData appendData:[NSMutableData dataWithLength:len]];
            }else if ([arguments[i] isKindOfClass:[NSData class]]) {
                [argData appendData:arguments[i]];
            }
            idx++;
        }
        _data = [argData copy];
    }
    return self;
}

- (NSData *)data {
    return _data;
}

- (id)objectAtIndexedSubscript:(NSUInteger)idx {
    NSAssert(idx >= 0 && idx < _arguments.count, @"index out bounds");
    return _arguments[idx];
}

@end

@implementation AYBLECommandResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYBLECommandResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.result = t.result;
        }
    }
    return self;
}

@end



@implementation AYNetConfigReq

+ (NSArray<NSString *> *)propertyNames { return @[@"ssid",@"pw",@"pk",@"timezone"]; }

- (NSData *)data {
    AYNetConfigReq_t t = {0};
    strcpy((char *)t.ssid, self.ssid.UTF8String);
    strcpy((char *)t.pw, self.pw.UTF8String);
    strcpy((char *)t.pk, self.pk.UTF8String);
    t.timezone = self.timezone;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end

@implementation AYAddFingerprintReq

- (instancetype)initWithArguments:(NSArray *)arguments {
    if (self = [super init]) {
        [self setValue:arguments forKey:@"user_id"];
    }
    return self;
}

- (NSData *)data {
    AYAddFingerprintReq_t t = {0};
    t.user_id = self.user_id;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end

@implementation AYDelFingerprintReq

+ (NSArray<NSString *> *)propertyNames { return @[@"pwd_id"]; }

- (NSData *)data {
    AYDelFingerprintReq_t t = {0};
    t.pwd_id = self.pwd_id;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end
@implementation AYFingerprintProgressResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYFingerprintProgressResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.percentage = t.percentage;
            self.state = t.state;
            self.pwd_id = t.pwd_id;
        }
    }
    return self;
}

@end

@implementation AYRemoteUnlockReq

+ (NSArray<NSString *> *)propertyNames { return @[@"user_id"]; }

- (NSData *)data {
    AYRemoteUnlockReq_t t = {0};
    t.user_id = self.user_id;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end

@implementation AYAddPasswordReq

+ (NSArray<NSString *> *)propertyNames { return @[@"pwd_type",@"period",@"start_min",@"end_min",@"start_timestamp",@"end_timestamp",@"passwd"]; }

- (NSData *)data {
    AYAddPasswordReq_t t = {0};
    t.pwd_type = self.pwd_type;
    t.period = self.period;
    t.start_min = self.start_min;
    t.end_min = self.end_min;
    t.start_timestamp = self.start_timestamp;
    t.end_timestamp = self.end_timestamp;
    strcpy((char *)t.passwd, self.passwd.UTF8String);
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end

@implementation AYAddPasswordResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYAddPasswordResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.new_id = t.new_id;
            self.err_no = t.err_no;
            self.type = t.type;
        }
    }
    return self;
}
@end

@implementation AYDelPasswordReq

+ (NSArray<NSString *> *)propertyNames { return @[@"ID",@"period",@"user_id"]; }


- (NSData *)data {
    AYDelPasswordReq_t t = {0};
    t.ID = self.ID;
    t.user_id = self.user_id;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}
@end

@implementation AYPasswordResp

+ (NSArray<AYPasswordResp *> *)listWithData:(NSData *)data {
    if (data.length > 2) {
        uint16_t count = 0;
        [data getBytes:&count range:NSMakeRange(0, 2)];
        int headerLen = 2;
        NSMutableArray *list = [NSMutableArray arrayWithCapacity:count];
        if (count*sizeof(AYPasswordResp_t)+headerLen == data.length) {
            for (int i = 0; i < count; i++) {
                AYPasswordResp_t t = {0};
                [data getBytes:&t range:NSMakeRange(headerLen+i*sizeof(t), sizeof(t))];
                AYPasswordResp* m = [AYPasswordResp new];
                m.unlock_type = t.unlock_type;
                m.pwd_id = t.pwd_id;
                [list addObject:m];
            }
        }
        return [list copy];
    }
    return @[];
}

@end

@implementation AYAdminPwdUpdateReq

+ (NSArray<NSString *> *)propertyNames { return @[@"old_password",@"ne_password"]; }

- (NSData *)data {
    AYAdminPwdUpdateReq_t t = {0};
    strcpy((char *)t.old_password, self.old_password.UTF8String);
    strcpy((char *)t.new_password, self.ne_password.UTF8String);
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end

@implementation AYUnlockEventResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYUnlockEventResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.local_timestamp = t.local_timestamp;
            self.event_id = t.event_id;
            self.key_id = t.key_id;
            self.unlock_type = t.unlock_type;
            self.hijack_flag = t.hijack_flag;
        }
    }
    return self;
}

@end

@implementation AYLockEventResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYLockEventResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.local_timestamp = t.local_timestamp;
            self.event_id = t.event_id;
            self.lock_type = t.lock_type;
        }
    }
    return self;
}
@end

@implementation AYLowPowerEventResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYLowPowerEventResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.local_timestamp = t.local_timestamp;
            self.event_id = t.event_id;
            self.power_value = t.power_value;
        }
    }
    return self;
}

@end

@implementation AYAlterPwdEventResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYAlterPwdEventResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.local_timestamp = t.local_timestamp;
            self.event_id = t.event_id;
            self.user_id = t.user_id;
            self.key_id = t.key_id;
        }
    }
    return self;
}

@end

@implementation AYUnlockExptEventResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYUnlockExptEventResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.local_timestamp = t.local_timestamp;
            self.event_id = t.event_id;
            self.alarm_type = t.alarm_type;
        }
    }
    return self;
}

@end

@implementation AYAddPwdEventResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYAddPwdEventResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.local_timestamp = t.local_timestamp;
            self.event_id = t.event_id;
            self.type = t.type;
            self.key_id = t.key_id;
        }
    }
    return self;
}

@end

@implementation AYDelPwdEventResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYDelPwdEventResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.local_timestamp = t.local_timestamp;
            self.event_id = t.event_id;
            self.type = t.type;
            self.key_id = t.key_id;
        }
    }
    return self;
}

@end

@implementation AYCommonEventResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYCommonEventResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.local_timestamp = t.local_timestamp;
            self.event_id = t.event_id;
        }
    }
    return self;
}

@end

@implementation AYAutoReplySetReq

+ (NSArray<NSString *> *)propertyNames { return @[@"enable",@"period",@"start_min",@"auto_res_id"]; }

- (NSData *)data {
    AYAutoReplySetReq_t t = {0};
    t.enable = self.enable;
    t.period = self.period;
    t.start_min = self.start_min;
    t.auto_res_id = self.auto_res_id;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end

@implementation AYAutoReplyGetResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYAutoReplyGetResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.enable = t.enable;
            self.period = t.period;
            self.start_min = t.start_min;
            self.end_min = t.end_min;
            self.auto_res_id = t.auto_res_id;
        }
    }
    return self;
}
@end

@implementation AYHijackCertSetReq

+ (NSArray<NSString *> *)propertyNames { return @[@"ID",@"type"]; }

- (NSData *)data {
    AYHijackCertSetReq_t t = {0};
    t.ID = self.ID;
    t.type = self.type;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end

@implementation AYLockPowerGetResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYLockPowerGetResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.battery_value = t.battery_value;
            self.power_value = t.power_value;
        }
    }
    return self;
}

@end

@implementation AYLockVolume

+ (NSArray<NSString *> *)propertyNames { return @[@"voice_volume",@"doorbell_volume"]; }
- (NSData *)data {
    AYLockVolume_t t = {0};
    t.voice_volume = self.voice_volume;
    t.doorbell_volume = self.doorbell_volume;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYLockVolume_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.voice_volume = t.voice_volume;
            self.doorbell_volume = t.doorbell_volume;
        }
    }
    return self;
}
@end

@implementation AYLockVersionInfoResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYLockVersionInfoResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.front_ver = [[NSString alloc] initWithCString:(const char*)t.front_ver encoding:NSUTF8StringEncoding];
            self.rear_ver = [[NSString alloc] initWithCString:(const char*)t.rear_ver encoding:NSUTF8StringEncoding];
            self.model = [[NSString alloc] initWithCString:(const char*)t.model encoding:NSUTF8StringEncoding];
        }
    }
    return self;
}
@end

@implementation AYAutoLockParam

+ (NSArray<NSString *> *)propertyNames { return @[@"auto_lock_time"]; }

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYAutoLockParam_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.auto_lock_time = t.auto_lock_time;
        }
    }
    return self;
}

- (NSData *)data {
    AYAutoLockParam_t t = {0};
    t.auto_lock_time = self.auto_lock_time;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}
@end

@implementation AYOTAUpgradeReq

+ (NSArray<NSString *> *)propertyNames { return @[@"lock_front_fw",@"front_fw_data_len",@"lock_rear_fw"]; }

- (NSData *)data {
    AYOTAUpgradeReq_t t = {0};
    t.lock_front_fw = self.lock_front_fw;
    t.lock_rear_fw = self.lock_rear_fw;
    t.front_fw_data_len = self.front_fw_data_len;
    t.rear_fw_data_len = self.rear_fw_data_len;
    return [NSData dataWithBytes:&t length:sizeof(t)];
}

@end

@implementation AYOTARequestReq

+ (NSArray<NSString *> *)propertyNames { return @[@"lock_fw_type",@"pack_no",@"fw_data"]; }

- (NSData *)data {
    NSMutableData *data = [NSMutableData data];
    uint8_t lock_fw_type = self.lock_fw_type;
    uint16_t pack_no = self.pack_no;
    [data appendBytes:&lock_fw_type length:sizeof(lock_fw_type)];
    [data appendBytes:&pack_no length:sizeof(pack_no)];
    [data appendData:self.fw_data];
    return [data copy];
}
@end

@implementation AYBindLockResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYBindLockResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.result = t.result;
            self.key = [NSData dataWithBytes:(const char *)t.key length:sizeof(t) - 2];
        }
    }
    return self;
}
@end

@implementation AYUnbindLockReq

+ (NSArray<NSString *> *)propertyNames { return @[@"key"]; }

- (NSData *)data {
    return self.key;
}

@end

@implementation AYKeyCheckReq

+ (NSArray<NSString *> *)propertyNames { return @[@"key"]; }

- (NSData *)data {
    return self.key;
}

@end

@implementation AYRandCodeResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length) {
            AYRandCodeResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.random_code = t.random_code;
        }
    }
    return self;
}
@end
@implementation AYAdminPwdSetReq

+ (NSArray<NSString *> *)propertyNames { return @[@"passwd"]; }

- (NSData *)data {
    return [self.passwd dataUsingEncoding:NSUTF8StringEncoding];
}

@end

@implementation AYLockInfoResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length == sizeof(AYLockInfoResp_t)) {
            AYLockInfoResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.serial_number = [[NSString alloc] initWithCString:(const char*)t.serial_number encoding:NSUTF8StringEncoding];
            self.secret_key = [[NSString alloc] initWithCString:(const char*)t.secret_key encoding:NSUTF8StringEncoding];
            self.product_id = [[NSString alloc] initWithCString:(const char*)t.product_id encoding:NSUTF8StringEncoding];
        }
    }
    return self;
}


@end

@implementation AYLockAllAttrResp

- (instancetype)initWithData:(NSData *)data {
    if (self = [super init]) {
        if (data.length == sizeof(AYLockAllAttrResp_t)) {
            AYLockAllAttrResp_t t = {0};
            [data getBytes:&t length:sizeof(t)];
            self.auto_lock_time = t.auto_lock_time;
            self.holiday_mode = t.holiday_mode;
            self.batt = [[AYLockPowerGetResp alloc] initWithData:[NSData dataWithBytes:&t.batt length:sizeof(t.batt)]];
            self.doorbell_volume = t.doorbell_volume;
            self.res = [[AYAutoReplyGetResp alloc] initWithData:[NSData dataWithBytes:&t.res length:sizeof(t.res)]];
            self.auto_lock_enable = t.auto_lock_enable;
            self.bt_mac_addr = [NSData dataWithBytes:(const void *)t.bt_mac_addr length:6].ay_hex.lowercaseString;
            self.info = [[AYLockVersionInfoResp alloc] initWithData:[NSData dataWithBytes:&t.info length:sizeof(t.info)]];
            self.admin_status = t.admin_status;
            self.volume = t.volume;
        }
    }
    return self;
}

@end

@implementation AYUnLockLockEventResp

+ (NSArray<AYUnLockLockEventResp *> *)listWithData:(NSData *)data remain:(uint16_t *)remain {
    if (data.length > 4) {
        uint16_t count = 0;
        [data getBytes:&count range:NSMakeRange(0, 2)];
        [data getBytes:remain range:NSMakeRange(2, 2)];
        int headerLen = 4;
        NSMutableArray *list = [NSMutableArray arrayWithCapacity:count];
        if (count*sizeof(AYUnLockLockEventResp_t)+headerLen == data.length) {
            for (int i = 0; i < count; i++) {
                AYUnLockLockEventResp_t t = {0};
                [data getBytes:&t range:NSMakeRange(headerLen+i*sizeof(t), sizeof(t))];
                AYUnLockLockEventResp *m = [AYUnLockLockEventResp new];
                m.local_timestamp = t.local_timestamp;
                m.event_id = t.event_id;
                m.key_id = t.key_id;
                m.sw = t.sw;
                m.type = t.type;
                [list addObject:m];
            }
        }
        return [list copy];
    }
    *remain = 0;
    return @[];
}

@end

@implementation AYAlarmEventResp

+ (NSArray<AYAlarmEventResp *> *)listWithData:(NSData *)data remain:(uint16_t *)remain {
    if (data.length > 4) {
        uint16_t count = 0;
        [data getBytes:&count range:NSMakeRange(0, 2)];
        [data getBytes:remain range:NSMakeRange(2, 2)];
        int headerLen = 4;
        NSMutableArray *list = [NSMutableArray arrayWithCapacity:count];
        if (count*sizeof(AYAlarmEventResp_t)+headerLen == data.length) {
            for (int i = 0; i < count; i++) {
                AYAlarmEventResp_t t = {0};
                [data getBytes:&t range:NSMakeRange(headerLen+i*sizeof(t), sizeof(t))];
                AYAlarmEventResp *m = [AYAlarmEventResp new];
                m.local_timestamp = t.local_timestamp;
                m.event_id = t.event_id;
                m.type = t.type;
                [list addObject:m];
            }
        }
        return [list copy];
    }
    *remain = 0;
    return @[];
}

@end
